//**********************************************************************
//	Programmer	-	Sujal Bista
//	File Name	-	modelDX.cpp
//	Description	:	
//					DirectX .x mesh importer
//
//**********************************************************************



#include "modelDX.h"
#include "bucketList.h"


#ifdef _USE_DIRECTX_

	// Direct3D9 includes
	#include <d3d9.h>
	#include <d3dx9.h>

	//#pragma comment(lib, "d3dx9.lib")
	#pragma comment(lib, "d3d9.lib")
	#pragma comment(lib, "dxerr.lib")		//direct error
#endif

#ifdef _MSC_VER
	#ifdef _DEBUG
		#define DEBUG_NEW new(_NORMAL_BLOCK ,__FILE__, __LINE__)
		#define new DEBUG_NEW
	#else
		#define DEBUG_NEW new
	#endif
#endif

#ifdef _USE_DIRECTX_

	#ifndef SAFE_DELETE
	#define SAFE_DELETE(p)       { if (p) { delete (p);     (p)=NULL; } }
	#endif    
	#ifndef SAFE_DELETE_ARRAY
	#define SAFE_DELETE_ARRAY(p) { if (p) { delete[] (p);   (p)=NULL; } }
	#endif    
	#ifndef SAFE_RELEASE
	#define SAFE_RELEASE(p)      { if (p) { (p)->Release(); (p)=NULL; } }
	#endif

	bucketList<model::mesh> meshList;
	bucketList<model::skin> skinList;

	//derived frame class
	struct D3DXFRAME_DERIVED : public D3DXFRAME
	{
	};
	//derived mesh container
	struct D3DXMESHCONTAINER_DERIVED : public D3DXMESHCONTAINER
	{
	};
	//prints to the output stream
	std::ostream& operator<<(std::ostream &out, const D3DXMATRIX& mat)
	{
		out<<mat.m[0][0]<<"\t"<<mat.m[0][1]<<"\t"<<mat.m[0][2]<<"\t"<<mat.m[0][3]<<"\t"<<"\n";
		out<<mat.m[1][0]<<"\t"<<mat.m[1][1]<<"\t"<<mat.m[1][2]<<"\t"<<mat.m[1][3]<<"\t"<<"\n";
		out<<mat.m[2][0]<<"\t"<<mat.m[2][1]<<"\t"<<mat.m[2][2]<<"\t"<<mat.m[2][3]<<"\t"<<"\n";
		out<<mat.m[3][0]<<"\t"<<mat.m[3][1]<<"\t"<<mat.m[3][2]<<"\t"<<mat.m[3][3]<<"\t"<<std::endl;
		return out;
	}

	//prints to the output stream
	std::ostream& operator<<(std::ostream &out, const D3DXVECTOR3& vec)
	{
		out<<"<"<<vec.x<<", "<<vec.y<<", "<<vec.z<<">";
		return out;
	}

	struct CUSTOMVERTEX
	{
		float x,y,z; // vertex position
		float nx,ny,nz; // vertex normal
		float tu,tv; // texture co-ordinate
	};

	//prints to the output stream
	std::ostream& operator<<(std::ostream &out, const CUSTOMVERTEX& vec)
	{
		out<<"<"<<vec.x<<", "<<vec.y<<", "<<vec.z<<","<<vec.nx<<", "<<vec.ny<<", "<<vec.nz<<", "<<vec.tu<<", "<<vec.tv<<">";
		return out;
	}

	//prints to the output stream
	std::ostream& operator<<(std::ostream &out, const D3DXKEY_VECTOR3& vec)
	{
		out<<"<kv "<<vec.Time<<"\t"<<vec.Value.x<<", "<<vec.Value.y<<", "<<vec.Value.z<<">";
		return out;
	}

	//prints to the output stream
	std::ostream& operator<<(std::ostream &out, const D3DXKEY_QUATERNION& vec)
	{
		out<<"<kq "<<vec.Time<<"\t"<<vec.Value.x<<", "<<vec.Value.y<<", "<<vec.Value.z<<", "<<vec.Value.w<<">";
		return out;
	}

	//import x file mesh
	void importXFileMesh(LPCSTR name,CONST D3DXMESHDATA *meshData, CONST D3DXMATERIAL *materialData, unsigned int materialCount,LPD3DXSKININFO skinData,CONST DWORD *pAdjacency)
	{

		LPD3DXMESH pMesh=meshData->pMesh;
		LPDIRECT3DDEVICE9 pd3dDevice = NULL;
		pMesh->GetDevice(&pd3dDevice);

		//create a mesh
		model::mesh tempMesh;
		meshList.addBack(tempMesh);
		model::mesh &currentMesh=meshList[meshList.size()-1];

		//copy name
		if(name)
		{
			strncpy(currentMesh.name,name,MAX_NAME);
			currentMesh.name[MAX_NAME-1]=NULL;
		}
		else
			currentMesh.name[0]=NULL;
	
		LPD3DXMESH fullMesh;

		//clone the mesh to make room for the normals
		HRESULT hr = pMesh->CloneMeshFVF(pMesh->GetOptions(),D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_TEX1,pd3dDevice,&fullMesh);
		if(FAILED( hr ))
			return;

		// now generate the normals for the pmesh
		D3DXComputeNormals( fullMesh, NULL );

		//out<<Name<<endl;
		//out<<pFrame->TransformationMatrix.m[0][0]<<endl;
		//out<<pFrame->CombinedTransformationMatrix<<endl;
		////////////////////////////////////////////////////////////
		//print vertices
		{		
			CUSTOMVERTEX* cVertices=NULL;
			fullMesh->LockVertexBuffer(D3DLOCK_READONLY, (void**)&cVertices);
			unsigned int vertexCount=fullMesh->GetNumVertices();

			//allocate space
			currentMesh.vertexCount=vertexCount;
			currentMesh.vertices=new model::mesh::vertex[currentMesh.vertexCount];

			//out<<"Vertices"<<endl;
			for (unsigned i=0; i<vertexCount;i++)
			{
				currentMesh.vertices[i].position.x=cVertices[i].x;
				currentMesh.vertices[i].position.y=cVertices[i].y;
				currentMesh.vertices[i].position.z=cVertices[i].z;

				currentMesh.vertices[i].normal.x=cVertices[i].nx;
				currentMesh.vertices[i].normal.y=cVertices[i].ny;
				currentMesh.vertices[i].normal.z=cVertices[i].nz;

				currentMesh.vertices[i].texCoord.x=cVertices[i].tu;
				currentMesh.vertices[i].texCoord.y=cVertices[i].tv;

				//out<<cVertices[i]<<endl;
			}
			fullMesh->UnlockVertexBuffer();
		}
		////////////////////////////////////////////////////////////

		////////////////////////////////////////////////////////////
		//print attributes
		{
			DWORD *attributes = NULL;
			fullMesh->LockAttributeBuffer(D3DLOCK_READONLY, &attributes );
			WORD *indices=NULL;
			fullMesh->LockIndexBuffer(D3DLOCK_READONLY, (void**)&indices);
			unsigned int faceCount=fullMesh->GetNumFaces();


			//allocate space
			currentMesh.faceCount=faceCount;
			currentMesh.faces=new model::mesh::face[currentMesh.faceCount];

			//out<<"Attributes and indices "<<endl;
			for (unsigned i=0; i<faceCount;i++)
			{
				currentMesh.faces[i].materialIndex=(unsigned int)attributes[i];

				currentMesh.faces[i].vertexIndex[0]=indices[i*3];
				currentMesh.faces[i].vertexIndex[1]=indices[i*3+2];
				currentMesh.faces[i].vertexIndex[2]=indices[i*3+1];

				currentMesh.faces[i].adjacency[0]=pAdjacency[i*3];
				currentMesh.faces[i].adjacency[1]=pAdjacency[i*3+2];
				currentMesh.faces[i].adjacency[2]=pAdjacency[i*3+1];

				//out<<attributes[i]<<"\t"<<((int)indices[i*3])<<"\t"<<((int)indices[i*3+1])<<"\t"<<((int)indices[i*3+2])<<endl;
			}
			fullMesh->UnlockAttributeBuffer();
			fullMesh->UnlockIndexBuffer();
		}
		////////////////////////////////////////////////////////////
		fullMesh->Release();
		pd3dDevice->Release();


		////////////////////////////////////////////////////////////
		//print the name of the materials
		currentMesh.materialCount=materialCount;
		currentMesh.materials=new model::mesh::material[currentMesh.materialCount];
		for(unsigned int i=0;i<materialCount;i++ )
		{
			if(materialData[i].pTextureFilename!=NULL)
			{
				unsigned int nameLength=(unsigned int)strlen(materialData[i].pTextureFilename);
				//currentMesh.materials[i].fileName=new char[nameLength+1];
				strncpy(currentMesh.materials[i].fileName,materialData[i].pTextureFilename,MAX_FILE_NAME);
				currentMesh.materials[i].fileName[MAX_FILE_NAME-1]='\0';//put null at the end

				//change the filename
				char *ptr=NULL;
				if(strstr(currentMesh.materials[i].fileName,".jpg"))
					ptr=strstr(currentMesh.materials[i].fileName,".jpg");
				else if(strstr(currentMesh.materials[i].fileName,".dds"))
					ptr=strstr(currentMesh.materials[i].fileName,".dds");
				if(ptr)
					strcpy(ptr,".bmp");

				//read in the texture
				//currentMesh.materials[i].image.open(currentMesh.materials[i].fileName);

				//out<<materialData[i].pTextureFilename<<endl;			
			}

			//copy material color
			currentMesh.materials[i].diffuse.r=materialData[i].MatD3D.Diffuse.r;
			currentMesh.materials[i].diffuse.g=materialData[i].MatD3D.Diffuse.g;
			currentMesh.materials[i].diffuse.b=materialData[i].MatD3D.Diffuse.b;
			currentMesh.materials[i].diffuse.a=materialData[i].MatD3D.Diffuse.a;

			currentMesh.materials[i].ambient.r=materialData[i].MatD3D.Ambient.r;
			currentMesh.materials[i].ambient.g=materialData[i].MatD3D.Ambient.g;
			currentMesh.materials[i].ambient.b=materialData[i].MatD3D.Ambient.b;

			currentMesh.materials[i].specular.r=materialData[i].MatD3D.Specular.r;
			currentMesh.materials[i].specular.g=materialData[i].MatD3D.Specular.g;
			currentMesh.materials[i].specular.b=materialData[i].MatD3D.Specular.b;

			currentMesh.materials[i].emissive.r=materialData[i].MatD3D.Emissive.r;
			currentMesh.materials[i].emissive.g=materialData[i].MatD3D.Emissive.g;
			currentMesh.materials[i].emissive.b=materialData[i].MatD3D.Emissive.b;

			currentMesh.materials[i].power=materialData[i].MatD3D.Power;
		}
		////////////////////////////////////////////////////////////

		// if there is skinning information, save off the required data and then setup for HW skinning
		if(skinData)
		{
			//create a mesh
			model::skin tempSkin;
			skinList.addBack(tempSkin);
			model::skin &currentSkin=skinList[skinList.size()-1];
			//model::skin &currentSkin=*(skinList.addBack());

			//get number of bones
			unsigned int boneCount = skinData->GetNumBones();
			currentSkin.boneCount=boneCount;
			currentSkin.bones=new model::skin::bone[currentSkin.boneCount];

			//print their offsets
			for(unsigned int i=0;i<boneCount;i++)
			{
				D3DXMATRIX offsetMatrix=*(skinData->GetBoneOffsetMatrix(i));
				unsigned int boneInfluenceCount=skinData->GetNumBoneInfluences(i);
				DWORD *vertices=new DWORD[boneInfluenceCount];
				float *weights=new float[boneInfluenceCount];
				skinData->GetBoneInfluence(i,vertices,weights);

				//copy the bone name
				LPCSTR boneName=skinData->GetBoneName(i);

				strncpy(currentSkin.bones[i].name,boneName,MAX_NAME);
				currentSkin.bones[i].name[MAX_NAME-1]=NULL;


				//copy offset matrix
				currentSkin.bones[i].offsetMatrix._00=offsetMatrix._11;
				currentSkin.bones[i].offsetMatrix._01=offsetMatrix._12;
				currentSkin.bones[i].offsetMatrix._02=offsetMatrix._13;
				currentSkin.bones[i].offsetMatrix._03=offsetMatrix._14;
				currentSkin.bones[i].offsetMatrix._10=offsetMatrix._21;
				currentSkin.bones[i].offsetMatrix._11=offsetMatrix._22;
				currentSkin.bones[i].offsetMatrix._12=offsetMatrix._23;
				currentSkin.bones[i].offsetMatrix._13=offsetMatrix._24;
				currentSkin.bones[i].offsetMatrix._20=offsetMatrix._31;
				currentSkin.bones[i].offsetMatrix._21=offsetMatrix._32;
				currentSkin.bones[i].offsetMatrix._22=offsetMatrix._33;
				currentSkin.bones[i].offsetMatrix._23=offsetMatrix._34;
				currentSkin.bones[i].offsetMatrix._30=offsetMatrix._41;
				currentSkin.bones[i].offsetMatrix._31=offsetMatrix._42;
				currentSkin.bones[i].offsetMatrix._32=offsetMatrix._43;
				currentSkin.bones[i].offsetMatrix._33=offsetMatrix._44;

				currentSkin.bones[i].influenceCount=boneInfluenceCount;
				//allocate space
				currentSkin.bones[i].vertexIndex=new unsigned int[currentSkin.bones[i].influenceCount];
				currentSkin.bones[i].weights=new float[currentSkin.bones[i].influenceCount];


				for(unsigned int j=0;j<boneInfluenceCount;j++)
				{
					//out<<vertices[j]<<"\t"<<weights[j]<<endl;
					currentSkin.bones[i].vertexIndex[j]=vertices[j];
					currentSkin.bones[i].weights[j]=weights[j];
				}
				delete[]vertices;
				delete[]weights;
			}
		}
	}

	//imports x file animation
	void importXFileAnimation(LPD3DXFRAME pFrame,ID3DXAnimationController *animationController, model &mContainer)
	{
		//out<<"Animation Data Start"<<endl;
		unsigned int animationSetCount=animationController->GetNumAnimationSets();
	
		mContainer.staticMeshHeader.animationCount=animationSetCount;
		mContainer.staticMeshHeader.animations=new model::animation[mContainer.staticMeshHeader.animationCount];


		for(unsigned int i=0;i<animationSetCount;i++)
		{
			ID3DXKeyframedAnimationSet* pKeyFrameAnimSet;
			animationController->GetAnimationSet(i, (ID3DXAnimationSet**)&pKeyFrameAnimSet);
			unsigned int animationCount=pKeyFrameAnimSet->GetNumAnimations();
		
			LPCSTR pName=pKeyFrameAnimSet->GetName();
		
			strncpy(mContainer.staticMeshHeader.animations[i].name,pName,MAX_NAME);
			mContainer.staticMeshHeader.animations[i].name[MAX_NAME-1]=NULL;

			mContainer.staticMeshHeader.animations[i].ticksPerSecond=(float)pKeyFrameAnimSet->GetSourceTicksPerSecond();
			mContainer.staticMeshHeader.animations[i].boneAnimationCount=animationCount;
			mContainer.staticMeshHeader.animations[i].boneAnimations=new model::animation::boneAnimation[mContainer.staticMeshHeader.animations[i].boneAnimationCount];

			for(unsigned int j=0;j<animationCount;j++)
			{
				LPCSTR pName=NULL;
				pKeyFrameAnimSet->GetAnimationNameByIndex(j,&pName);
				//out<<pName<<endl;
				unsigned int scaleKeysCount=pKeyFrameAnimSet->GetNumScaleKeys(j);
				unsigned int rotKeysCount=pKeyFrameAnimSet->GetNumRotationKeys(j);
				unsigned int transKeysCount=pKeyFrameAnimSet->GetNumTranslationKeys(j);


				D3DXKEY_VECTOR3 *pScale=new D3DXKEY_VECTOR3[scaleKeysCount];
				D3DXKEY_QUATERNION *pRotation=new D3DXKEY_QUATERNION[rotKeysCount];
				D3DXKEY_VECTOR3 *pTranslation=new D3DXKEY_VECTOR3[transKeysCount];

				pKeyFrameAnimSet->GetScaleKeys(j,pScale);
				pKeyFrameAnimSet->GetRotationKeys(j,pRotation);
				pKeyFrameAnimSet->GetTranslationKeys(j,pTranslation);

				model::animation::boneAnimation &currBoneAnimation=mContainer.staticMeshHeader.animations[i].boneAnimations[j];

				strncpy(currBoneAnimation.name,pName,MAX_NAME);
				currBoneAnimation.name[MAX_NAME-1]=NULL;
			
				currBoneAnimation.scaleCount=scaleKeysCount;
				currBoneAnimation.rotationCount=rotKeysCount;
				currBoneAnimation.translationCount=transKeysCount;

				currBoneAnimation.scales=new model::animation::boneAnimation::float3SKey[currBoneAnimation.scaleCount];
				currBoneAnimation.rotations=new model::animation::boneAnimation::floatQuaternionKey[currBoneAnimation.rotationCount];
				currBoneAnimation.translations=new model::animation::boneAnimation::float3SKey[currBoneAnimation.translationCount];

				//scale
				//out<<"Scale Keys"<<endl;
				for(unsigned int j=0;j<scaleKeysCount;j++)
				{
					//out<<pScale[j]<<endl;
					currBoneAnimation.scales[j].time=pScale[j].Time;
					currBoneAnimation.scales[j].value.x=pScale[j].Value.x;
					currBoneAnimation.scales[j].value.y=pScale[j].Value.y;
					currBoneAnimation.scales[j].value.z=pScale[j].Value.z;
				}


				//rotation
				//out<<"Rotation Keys"<<endl;
				for(unsigned int j=0;j<rotKeysCount;j++)
				{
					//out<<pRotation[j]<<endl;
					currBoneAnimation.rotations[j].time=pRotation[j].Time;
					currBoneAnimation.rotations[j].value.x=pRotation[j].Value.x;
					currBoneAnimation.rotations[j].value.y=pRotation[j].Value.y;
					currBoneAnimation.rotations[j].value.z=pRotation[j].Value.z;
					currBoneAnimation.rotations[j].value.w=pRotation[j].Value.w;
				}

				//translation
				//out<<"Translation Keys"<<endl;
				for(unsigned int j=0;j<transKeysCount;j++)
				{
					//out<<pTranslation[j]<<endl;
					currBoneAnimation.translations[j].time=pTranslation[j].Time;
					currBoneAnimation.translations[j].value.x=pTranslation[j].Value.x;
					currBoneAnimation.translations[j].value.y=pTranslation[j].Value.y;
					currBoneAnimation.translations[j].value.z=pTranslation[j].Value.z;
				}


				delete[] pScale;
				delete[] pRotation;
				delete[] pTranslation;
			}
			pKeyFrameAnimSet->Release();
		}
		//out<<"Animation Data End"<<endl;
	}

	//computes bones hierarchy count
	void getBoneHierarchySize(LPD3DXFRAME pFrameBase, unsigned int &boneHierarchyCount)
	{
		D3DXFRAME_DERIVED* pFrame = ( D3DXFRAME_DERIVED* )pFrameBase;
		boneHierarchyCount++;
		if( pFrame->pFrameSibling)
			getBoneHierarchySize(pFrame->pFrameSibling,boneHierarchyCount);
		if( pFrame->pFrameFirstChild)
			getBoneHierarchySize(pFrame->pFrameFirstChild,boneHierarchyCount);
	}

	//imports x file bone hierarchy
	void importXFileBoneHierarchy(LPD3DXFRAME pFrameBase, unsigned int currIndex ,model::skin::boneHierarchy *&bonesHierarchy,unsigned int &bonesHierarchyIndex)
	{
		model::skin::boneHierarchy &bHierarchy=bonesHierarchy[currIndex];
		D3DXFRAME_DERIVED* pFrame = ( D3DXFRAME_DERIVED* )pFrameBase;

		//allocate space for the name and copy the data
		strncpy(bHierarchy.name,pFrame->Name,MAX_NAME);
		bHierarchy.name[MAX_NAME-1]=NULL;

		//copy transformation matrix
		bHierarchy.transformationMatrix._00=pFrame->TransformationMatrix._11;
		bHierarchy.transformationMatrix._01=pFrame->TransformationMatrix._12;
		bHierarchy.transformationMatrix._02=pFrame->TransformationMatrix._13;
		bHierarchy.transformationMatrix._03=pFrame->TransformationMatrix._14;
		bHierarchy.transformationMatrix._10=pFrame->TransformationMatrix._21;
		bHierarchy.transformationMatrix._11=pFrame->TransformationMatrix._22;
		bHierarchy.transformationMatrix._12=pFrame->TransformationMatrix._23;
		bHierarchy.transformationMatrix._13=pFrame->TransformationMatrix._24;
		bHierarchy.transformationMatrix._20=pFrame->TransformationMatrix._31;
		bHierarchy.transformationMatrix._21=pFrame->TransformationMatrix._32;
		bHierarchy.transformationMatrix._22=pFrame->TransformationMatrix._33;
		bHierarchy.transformationMatrix._23=pFrame->TransformationMatrix._34;
		bHierarchy.transformationMatrix._30=pFrame->TransformationMatrix._41;
		bHierarchy.transformationMatrix._31=pFrame->TransformationMatrix._42;
		bHierarchy.transformationMatrix._32=pFrame->TransformationMatrix._43;
		bHierarchy.transformationMatrix._33=pFrame->TransformationMatrix._44;

		if( pFrame->pFrameSibling)
		{
			bHierarchy.siblingIndex=bonesHierarchyIndex++;
			importXFileBoneHierarchy(pFrame->pFrameSibling,bonesHierarchyIndex-1,bonesHierarchy,bonesHierarchyIndex);
		}
		if( pFrame->pFrameFirstChild)
		{
			bHierarchy.childIndex=bonesHierarchyIndex++;
			importXFileBoneHierarchy(pFrame->pFrameFirstChild,bonesHierarchyIndex-1,bonesHierarchy,bonesHierarchyIndex);
		}
	}

	//contum version of ID3DXAllocateHierarchy to create frames and mesh containter
	class CAllocateHierarchy : public ID3DXAllocateHierarchy
	{
		public:
			//allocates name
			HRESULT AllocateName( LPCSTR Name, LPSTR* pNewName )
			{
				UINT cbLength;

				if(Name)
				{
					cbLength = ( UINT )strlen( Name ) + 1;
					*pNewName = new CHAR[cbLength];
					if( *pNewName == NULL )
						return E_OUTOFMEMORY;
					memcpy( *pNewName, Name, cbLength * sizeof( CHAR ) );
				}
				else
				{
					*pNewName = NULL;
				}

				return S_OK;
			}

			//creates frame
			HRESULT CreateFrame( LPCSTR Name, LPD3DXFRAME* ppNewFrame )
			{
					HRESULT hr = S_OK;
					D3DXFRAME_DERIVED* pFrame;

					*ppNewFrame = NULL;

					pFrame = new D3DXFRAME_DERIVED;
					if( pFrame == NULL )
					{
						hr = E_OUTOFMEMORY;
						goto e_Exit;
					}

					hr = AllocateName( Name, &pFrame->Name );
					if( FAILED( hr ) )
						goto e_Exit;

					// initialize other data members of the frame
					D3DXMatrixIdentity( &pFrame->TransformationMatrix );

					pFrame->pMeshContainer = NULL;
					pFrame->pFrameSibling = NULL;
					pFrame->pFrameFirstChild = NULL;

					*ppNewFrame = pFrame;
					pFrame = NULL;

				e_Exit:
					delete pFrame;
					return hr;
			}
		
			//callback once the mesh is created
			HRESULT CreateMeshContainer(LPCSTR Name,CONST D3DXMESHDATA *pMeshData,CONST D3DXMATERIAL *pMaterials,CONST D3DXEFFECTINSTANCE *pEffectInstances,DWORD NumMaterials,CONST DWORD *pAdjacency,LPD3DXSKININFO pSkinInfo,LPD3DXMESHCONTAINER *ppNewMeshContainer)
			{
				//import x file mesh
				importXFileMesh(Name,pMeshData,pMaterials,NumMaterials,pSkinInfo,pAdjacency);
				D3DXMESHCONTAINER_DERIVED *pMeshContainer=new D3DXMESHCONTAINER_DERIVED;
				memset( pMeshContainer, 0, sizeof( D3DXMESHCONTAINER_DERIVED ) );
				*ppNewMeshContainer = pMeshContainer;
				pMeshContainer = NULL;
				return S_OK;
			}

			//destroys frame
			HRESULT DestroyFrame( LPD3DXFRAME pFrameToFree )
			{
				SAFE_DELETE_ARRAY( pFrameToFree->Name );
				SAFE_DELETE( pFrameToFree );
				return S_OK;
			}

			//destryos mesh container
			HRESULT DestroyMeshContainer( LPD3DXMESHCONTAINER pMeshContainerBase )
			{	
				//UINT iMaterial;
				D3DXMESHCONTAINER_DERIVED* pMeshContainer = ( D3DXMESHCONTAINER_DERIVED* )pMeshContainerBase;

				SAFE_DELETE_ARRAY( pMeshContainer->Name );
				SAFE_DELETE_ARRAY( pMeshContainer->pAdjacency );
				SAFE_DELETE_ARRAY( pMeshContainer->pMaterials );
				SAFE_DELETE( pMeshContainer );
				return S_OK;
			}
			
			//destructor
			CAllocateHierarchy()
			{
			}
	};

#endif

//constructor
modelDX::modelDX(void)
{

}

//reads in x file
bool modelDX::importX(HWND hWnd, char *fileName)
{	

	//clear the mesh container
	clear();

	#ifdef _USE_DIRECTX_

		IDirect3D9* pD3D9 = Direct3DCreate9(D3D_SDK_VERSION);
		if(!pD3D9)
			return false;

		//clear the mesh list
		meshList.clear();
		skinList.clear();

		IDirect3DDevice9* pD3DDevice9=NULL;
		LPD3DXFRAME                 g_pFrameRoot = NULL;
		ID3DXAnimationController*   g_pAnimController = NULL;
		CAllocateHierarchy Alloc;

		// get the display mode
		D3DDISPLAYMODE d3ddm;
		pD3D9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm);

		// set the presentation parameters
		D3DPRESENT_PARAMETERS d3dpp;
		ZeroMemory(&d3dpp, sizeof(d3dpp));
		d3dpp.BackBufferWidth = 10;
		d3dpp.BackBufferHeight = 10;
		d3dpp.BackBufferCount = 1;
		d3dpp.BackBufferFormat = d3ddm.Format;
		d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
		d3dpp.Windowed = true;
		d3dpp.EnableAutoDepthStencil = true;
		d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
		d3dpp.FullScreen_RefreshRateInHz = D3DPRESENT_RATE_DEFAULT;
		d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;


		if(FAILED(pD3D9->CreateDevice(D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL, hWnd,D3DCREATE_SOFTWARE_VERTEXPROCESSING,&d3dpp, &pD3DDevice9)))
			return false;

		WCHAR *fileNameWCHAR=ansiToUnicode(fileName);

		if(FAILED(D3DXLoadMeshHierarchyFromX(fileNameWCHAR, D3DXMESH_MANAGED, pD3DDevice9, &Alloc, NULL, &g_pFrameRoot, &g_pAnimController)))
		{
			delete[] fileNameWCHAR;
			return false;
		}

		delete[] fileNameWCHAR;

		//imports x file animation
		importXFileAnimation(g_pFrameRoot,g_pAnimController,*this);

		/////////////////////////////////////////////////////////////
		//copy the data
		staticMeshHeader.meshCount=meshList.size();//count;
		staticMeshHeader.meshes=new mesh[staticMeshHeader.meshCount];

		for(unsigned int i=0;i<meshList.size();i++)
			staticMeshHeader.meshes[i]=meshList[i];
	
		//copy the skin data
		if(skinList.size())
		{
			staticMeshHeader.skinCount=skinList.size();
			staticMeshHeader.skins=new skin[staticMeshHeader.skinCount];

			//copy the skins
			for(unsigned int i=0;i<skinList.size();i++)
				staticMeshHeader.skins[i]=skinList[i];		

			//fill in the skin data
			for(unsigned int i=0;i<staticMeshHeader.skinCount;i++)
			{
				//computes bones hierarchy count
				getBoneHierarchySize(g_pFrameRoot,staticMeshHeader.skins[i].boneHierarchyCount);
				staticMeshHeader.skins[i].bonesHierarchy=new skin::boneHierarchy[staticMeshHeader.skins[i].boneHierarchyCount];

				unsigned int bonesHierarchyIndex=0;
				//staticMeshHeader.skins[i].rootBone=&staticMeshHeader.skins[i].bonesHierarchy[bonesHierarchyIndex++];
				staticMeshHeader.skins[i].rootIndex=bonesHierarchyIndex++;
				//imports x file bone hierarchy
				importXFileBoneHierarchy(g_pFrameRoot,staticMeshHeader.skins[i].rootIndex,staticMeshHeader.skins[i].bonesHierarchy,bonesHierarchyIndex);
			}

			//link bones with boneHierarchy
			for(unsigned int i=0;i<staticMeshHeader.skinCount;i++)
				staticMeshHeader.skins[i].initialize();
		}


		//clear the skin and mesh list
		skinList.clear();
		meshList.clear();

		/////////////////////////////////////////////////////////////

		pD3DDevice9->Release();
		pD3D9->Release();

		D3DXFrameDestroy( g_pFrameRoot, &Alloc );
		SAFE_RELEASE( g_pAnimController );

		///////////////////////////////////////////////////////////////////

		//create one instace
		float4x4 temp;
		temp.identity();
		//instances.addBack(instance(&meshes[0],NULL,NULL,temp));
		instances.addBack(instance((modelQuick::meshData *)&staticMeshHeader.meshes[0],(modelQuick::skinData *)&staticMeshHeader.skins[0],(modelQuick::animationData *)&staticMeshHeader.animations[0],temp));
		//instances.addBack(instance(&meshes[1],&skins[0],&animations[0],temp));
		//temp.identity();
		//temp.translate(float3S(0.0,200.0,0.0));
		//temp=temp.transpose();
		//instances.addBack(instance(&meshes[1],&skins[0],&animations[1],temp));
		//temp.identity();
		//temp.translate(float3S(0.0,400.0,0.0));
		//temp=temp.transpose();
		//instances.addBack(instance(&meshes[1],&skins[0],&animations[2],temp));
		//temp.identity();
		//temp.translate(float3S(0.0,600.0,0.0));
		//temp=temp.transpose();
		//instances.addBack(instance(&meshes[1],&skins[0],&animations[3],temp));

		//initialize all the instances
		for(unsigned int i=0;i<instances.size();i++)
			instances[i].initialize();

	#endif
		
	return true;
}

//free the data
void modelDX::clear(void)
{
	model::clear();
}

//destructor
modelDX::~modelDX()
{
	//free the data
	clear();
}

